﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web;
using System.Xml;
using System.Xml.Serialization;
using System.Xml.XPath;

namespace YunLib.Common
{
    public static class ConvertExtensions
    {
        static CultureInfo USCulture = new CultureInfo("en-US");

        #region 类型转换
        public static T ConvertTo<T>(this object value) { return value.ConvertTo(default(T)); }
        public static T ConvertTo<T>(this object value, T defaultValue)
        {
            if (value != null)
            {
                var targetType = typeof(T);

                var converter = TypeDescriptor.GetConverter(value);
                if (converter != null)
                {
                    if (converter.CanConvertTo(targetType)) return (T)converter.ConvertTo(value, targetType);
                }

                converter = TypeDescriptor.GetConverter(targetType);
                if (converter != null)
                {
                    try { if (converter.CanConvertFrom(value.GetType())) return (T)converter.ConvertFrom(value); }
                    catch { }
                }
            }
            return defaultValue;
        }

        public static T ConvertTo<T>(this object value, T defaultValue, bool ignoreException)
        {
            if (ignoreException)
            {
                try
                {
                    return value.ConvertTo<T>();
                }
                catch
                {
                    return defaultValue;
                }
            }
            return value.ConvertTo<T>();
        }

        public static int ToInt(this object strValue, int defValue) { int def = 0; int.TryParse(strValue.ToString(), out def); return def == 0 ? defValue : def; }
        public static byte ToTinyInt(this object strValue, byte defValue) { byte def = 0; byte.TryParse(strValue.ToString(), out def); return def == 0 ? defValue : def; }
        public static short ToSmallInt(this object strValue, short defValue) { short def = 0; short.TryParse(strValue.ToString(), out def); return def == 0 ? defValue : def; }
        public static decimal ToDecimal(this object strValue, decimal defValue) { decimal def = 0; decimal.TryParse(strValue.ToString(), out def); return def == 0 ? defValue : def; }
        public static float ToFloat(this object strValue, float defValue) { float def = 0; float.TryParse(strValue.ToString(), out def); return def == 0 ? defValue : def; }
        public static Int64 ToBigInt(this object strValue, Int64 defValue) { Int64 def = 0; Int64.TryParse(strValue.ToString(), out def); return def == 0 ? defValue : def; }
        public static decimal ToMoney(this object strValue, decimal defValue) { decimal def = 0; decimal.TryParse(strValue.ToString(), out def); return def == 0 ? defValue : def; }
        public static int ToInteger(this object strValue, int defValue) { int def = 0; int.TryParse(strValue.ToString(), out def); return def == 0 ? defValue : def; }
        public static bool ToBool(this object Expression, bool defValue)
        {
            if (Expression != null)
            {
                if (string.Compare(Expression.ToString(), "true", true) == 0) return true;
                if (string.Compare(Expression.ToString(), "false", true) == 0) return false;
                if (string.Compare(Expression.ToString(), "1", true) == 0) return true;
                if (string.Compare(Expression.ToString(), "0", true) == 0) return false;
            }
            return defValue;
        }
        public static int ToInt(this object strValue) { return strValue.ToInt(0); }
        public static byte ToTinyInt(this object strValue) { return strValue.ToTinyInt(0); }
        public static short ToSmallInt(this object strValue) { return strValue.ToSmallInt(0); }
        public static decimal ToDecimal(this object strValue) { return strValue.ToDecimal(0); }
        public static float ToFloat(this object strValue) { return strValue.ToFloat(0); }
        public static Int64 ToBigInt(this object strValue) { return strValue.ToBigInt(0); }
        public static decimal ToMoney(this object strValue) { return strValue.ToMoney(0); }
        public static int ToInteger(this object strValue) { return strValue.ToInteger(0); }
        public static bool ToBool(this object strValue) { return strValue.ToBool(false); }

        #endregion

        #region 克隆对象

        public static T Clone<T>(this T obj, bool deep = false)
            where T : class,ISerializable, new()
        {
            if (deep)
            {
                MemoryStream stream = new MemoryStream();
                BinaryFormatter formatter = new BinaryFormatter();
                formatter.Serialize(stream, obj);
                stream.Position = 0;
                return formatter.Deserialize(stream) as T;
            }
            else
            {
                Type type = obj.GetType().BaseType;

                MethodInfo[] methodInfos = type.GetMethods(BindingFlags.NonPublic
                                | BindingFlags.Instance
                                | BindingFlags.DeclaredOnly);
                MethodInfo cloneMethod = null;
                foreach (var item in methodInfos)
                {
                    if (item.Name == "MemberwiseClone")
                    {
                        cloneMethod = item;
                        break;
                    }
                }
                if (cloneMethod != null) return (T)cloneMethod.Invoke(obj, null);
            }

            return default(T);
        }

        #endregion

        #region 反射
        public static object InvokeMethod(this object obj, string methodName, params object[] parameters)
        {
            return InvokeMethod<object>(obj, methodName, parameters);
        }

        public static T InvokeMethod<T>(this object obj, string methodName)
        {
            return InvokeMethod<T>(obj, methodName, null);
        }

        public static T InvokeMethod<T>(this object obj, string methodName, params object[] parameters)
        {
            var type = obj.GetType();
            var method = type.GetMethod(methodName);

            if (method == null) throw new ArgumentException(string.Format("Method '{0}' not found.", methodName), methodName);

            var value = method.Invoke(obj, parameters);
            return (value is T ? (T)value : default(T));
        }

        public static object GetPropertyValue(this object obj, string propertyName)
        {
            return GetPropertyValue<object>(obj, propertyName, null);
        }

        public static T GetPropertyValue<T>(this object obj, string propertyName)
        {
            return GetPropertyValue<T>(obj, propertyName, default(T));
        }

        public static T GetPropertyValue<T>(this object obj, string propertyName, T defaultValue)
        {
            var type = obj.GetType();
            var property = type.GetProperty(propertyName);

            if (property == null) throw new ArgumentException(string.Format("Property '{0}' not found.", propertyName), propertyName);

            var value = property.GetValue(obj, null);
            return (value is T ? (T)value : defaultValue);
        }

        public static void SetPropertyValue(this object obj, string propertyName, object value)
        {
            var type = obj.GetType();
            var property = type.GetProperty(propertyName);

            if (property == null) throw new ArgumentException(string.Format("Property '{0}' not found.", propertyName), propertyName);

            property.SetValue(obj, value, null);
        }

        public static T GetAttribute<T>(this object obj) where T : Attribute
        {
            return GetAttribute<T>(obj, true);
        }

        public static T GetAttribute<T>(this object obj, bool includeInherited) where T : Attribute
        {
            var type = (obj as Type ?? obj.GetType());
            var attributes = type.GetCustomAttributes(typeof(T), includeInherited);
            if ((attributes != null) && (attributes.Length > 0))
            {
                return (attributes[0] as T);
            }
            return null;
        }

        public static IEnumerable<T> GetAttributes<T>(this object obj) where T : Attribute
        {
            return GetAttributes<T>(obj);
        }

        public static IEnumerable<T> GetAttributes<T>(this object obj, bool includeInherited) where T : Attribute
        {
            var type = (obj as Type ?? obj.GetType());
            foreach (var attribute in type.GetCustomAttributes(typeof(T), includeInherited))
            {
                if (attribute is T) yield return (T)attribute;
            }
        }

        #endregion

        #region Xml序列化与反序列化
        /// <summary>
        /// 反序列化xml到指定对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        ///// <returns></returns>
        //public static T XmlDeserialize<T>(this string obj, Type Source = null, Type Target = null)
        //   where T : class , new()
        //{
        //    if (obj == null || obj.Length == 0 || obj.Trim().Length == 0) return new T();

        //    if (typeof(T).Name == "ReturnObject") throw new Exception("反序列化ReturnObject对象,请使用GetReturnObject()方法.");

        //    if (Target == null || Source == null)
        //        return MethodHelper.Deserialize<T>(obj);
        //    else
        //    {
        //        string result = obj;
        //        result = result.Replace("ArrayOf{0}".FormatWith(Source.Name), "ArrayOf{0}".FormatWith(Target.Name));
        //        result = result.Replace("<{0}>".FormatWith(Source.Name), "<{0}>".FormatWith(Target.Name));
        //        result = result.Replace("</{0}>".FormatWith(Source.Name), "</{0}>".FormatWith(Target.Name));
        //        result = result.Replace("&lt;{0}&gt;".FormatWith(Source.Name), "&lt;{0}&gt;".FormatWith(Target.Name));
        //        result = result.Replace("&lt;/{0}&gt;".FormatWith(Source.Name), "&lt;/{0}&gt;".FormatWith(Target.Name));
        //        return MethodHelper.Deserialize<T>(result); ;
        //    }
        //}

        public static string XmlSerializer<T>(T obj, string encode = "utf-8")
            where T : class, new()
        {
            string result = string.Empty;

            try
            {
                using (MemoryStream ms = new MemoryStream())
                {
                    XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));

                    xmlSerializer.Serialize(ms, obj);

                    result = Encoding.GetEncoding(encode).GetString(ms.ToArray());
                }
            }
            catch (Exception e)
            {
                throw e;
            }

            return result;
        }

        #endregion

        #region 字符串扩展

        /// <summary>
        /// 是否为空
        /// </summary>
        /// <param name="value">值</param>
        public static bool IsEmpty(this string value)
        {
            return string.IsNullOrWhiteSpace(value);
        }
        /// <summary>
        /// 是否为空
        /// </summary>
        /// <param name="value">值</param>
        public static bool IsEmpty(this Guid? value)
        {
            if (value == null)
                return true;
            return IsEmpty(value.Value);
        }
        /// <summary>
        /// 是否为空
        /// </summary>
        /// <param name="value">值</param>
        public static bool IsEmpty(this Guid value)
        {
            if (value == Guid.Empty)
                return true;
            return false;
        }
        /// <summary>
        /// 是否为空
        /// </summary>
        /// <param name="value">值</param>
        public static bool IsEmpty(this object value)
        {
            if (value != null && !string.IsNullOrEmpty(value.ToString()))
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        /// <summary>
        /// 过滤字符
        /// </summary>
        public static bool CheckSqlParameters(this string sInput)
        {
            if (sInput == null || sInput.Trim() == string.Empty)
                return true;
            string sInput1 = sInput.ToLower();
            string output = sInput;
            string pattern = @"*|exec|insert|select|delete|update|count|master|truncate|declare|char(|mid(|chr(|'";
            if (Regex.Match(sInput1, Regex.Escape(pattern), RegexOptions.Compiled | RegexOptions.IgnoreCase).Success)
            {
                throw new Exception("【{0}】字符串中含有非法字符!".FormatWith(sInput));
            }
            return true;
        }

        /// <summary>
        /// 扩展异常类方法
        /// </summary>
        /// <param name="ex"></param>
        /// <returns></returns>
        public static string GetCxMessage(this Exception ex)
        {
            return string.Format("【{0}】{1}", "CX", ex.Message);
        }

        /// <summary>
        /// 秒转小时分秒
        /// </summary>
        /// <param name="seconds"></param>
        /// <returns></returns>
        public static string SecondsToHoursMinutesSeconds(this int seconds)
        {
            TimeSpan ts = new TimeSpan(0, 0, Convert.ToInt32(seconds));
            string str = "";
            if (ts.Hours > 0 && ts.Minutes > 0 && ts.Seconds >0)
            {
                str = ts.Hours.ToString() + "小时 " + ts.Minutes.ToString() + "分钟 " + ts.Seconds + "秒";
            }
            else if (ts.Hours > 0 && ts.Minutes > 0)
            {
                str = ts.Hours.ToString() + "小时 " + ts.Minutes.ToString() + "分钟 ";
            }
            else if (ts.Hours > 0)
            {
                str = ts.Hours.ToString() + "小时 ";
            }
            else if (ts.Minutes > 0 && ts.Seconds > 0)
            {
                str = ts.Minutes.ToString() + "分钟 " + ts.Seconds + "秒";
            }
            else if (ts.Minutes > 0)
            {
                str = ts.Minutes.ToString() + "分钟 ";
            }
            else
            {
                str = ts.Seconds + "秒";
            }
            return str;
        }

        /// <summary>
        /// 字符串是否为空或空白字符
        /// </summary>
        /// <returns></returns>
        public static bool IsNullOrWhiteSpace(this String Str)
        {
            return Str == null || Str.Length == 0 || Str.Trim().Length == 0;
        }

        public static bool IsNullEmpty(this string str)
        {
            return string.IsNullOrEmpty(str);
        }
        public static string IsNullEmpty(this string str, string defaultValue)
        {
            return str.IsNullEmpty() ? defaultValue : str;
        }

        //public static XmlDocument GetXmlDocument(this string nXml)
        //{
        //    //生产xml文档结构
        //    XmlDocument xd = new XmlDocument();
        //    try
        //    {
        //        xd.LoadXml(nXml);
        //    }
        //    catch (Exception ex)
        //    {
        //        LoggerHelper.Error(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName + "=>" + ex.Message + "参数:" + nXml);
        //        throw;
        //    }
        //    return xd;
        //}

        public static String SQuote(this String s)
        {
            s.Filter();
            if (string.IsNullOrWhiteSpace(s)) return "''";
            int len = s.Length + 25;
            StringBuilder tmpS = new StringBuilder(len); // hopefully only one alloc
            tmpS.Append("N'");
            tmpS.Append(s.Replace("'", "''"));
            tmpS.Append("'");
            return tmpS.ToString();
        }

        public static object SqlSafeValue(this string str)
        {
            if (str == null)
                return DBNull.Value;
            else
                return str;
        }

        /// <summary>
        /// 过滤字符
        /// </summary>
        public static bool Filter(this string sInput)
        {
            if (sInput == null || sInput.Trim() == string.Empty)
                return true;
            string sInput1 = sInput.ToLower();
            string output = sInput;
            string pattern = @"*|and|exec|insert|select|delete|update|count|master|truncate|declare|char(|mid(|chr(|'";
            if (Regex.Match(sInput1, Regex.Escape(pattern), RegexOptions.Compiled | RegexOptions.IgnoreCase).Success)
            {
                throw new Exception("【{0}】字符串中含有非法字符!".FormatWith(sInput));
            }
            return true;
        }

        public static string UnHtml(this string htmlStr)
        {
            if (htmlStr.IsNullEmpty()) return string.Empty;
            return htmlStr.Replace("\"", "\\\"").ShowXmlHtml().Replace(" ", "&nbsp;").Replace("\n", "<br />");
        }
        public static string ShowXmlHtml(this string htmlStr)
        {
            if (htmlStr.IsNullEmpty()) return string.Empty;
            string str = htmlStr.Replace("&", "&amp;").Replace(">", "&gt;").Replace("<", "&lt;");
            return str;
        }
        public static string ShowHtml(this string htmlStr)
        {
            if (htmlStr.IsNullEmpty()) return string.Empty;
            string str = htmlStr;

            str = Regex.Replace(str, @"(script|frame|form|meta|behavior|style)([\s|:|>])+", "_$1.$2", RegexOptions.IgnoreCase);
            str = new Regex("<script", RegexOptions.IgnoreCase).Replace(str, "<_script");
            str = new Regex("<object", RegexOptions.IgnoreCase).Replace(str, "<_object");
            str = new Regex("javascript:", RegexOptions.IgnoreCase).Replace(str, "_javascript:");
            str = new Regex("vbscript:", RegexOptions.IgnoreCase).Replace(str, "_vbscript:");
            str = new Regex("expression", RegexOptions.IgnoreCase).Replace(str, "_expression");
            str = new Regex("@import", RegexOptions.IgnoreCase).Replace(str, "_@import");
            str = new Regex("<iframe", RegexOptions.IgnoreCase).Replace(str, "<_iframe");
            str = new Regex("<frameset", RegexOptions.IgnoreCase).Replace(str, "<_frameset");
            str = Regex.Replace(str, @"(\<|\s+)o([a-z]+\s?=)", "$1_o$2", RegexOptions.IgnoreCase);
            str = new Regex(@" (on[a-zA-Z ]+)=", RegexOptions.IgnoreCase).Replace(str, " _$1=");
            return str;
        }

        public static byte[] ToBytes(this string value)
        {
            return value.ToBytes(null);
        }

        public static byte[] ToBytes(this string value, Encoding encoding)
        {
            encoding = (encoding ?? Encoding.Default);
            return encoding.GetBytes(value);
        }

        public static string Reverse(this string value)
        {
            if (value.IsNullEmpty()) return string.Empty;

            var chars = value.ToCharArray();
            Array.Reverse(chars);
            return new string(chars);
        }

        //public static string UrlEncode(this string str)
        //{
        //    return HttpUtility.UrlEncode(str);
        //}

        //public static string UrlDecode(this string str)
        //{
        //    return HttpUtility.UrlDecode(str);
        //}

        //public static string HtmlEncode(this string str)
        //{
        //    return HttpUtility.HtmlEncode(str);
        //}

        //public static string HtmlDecode(this string str)
        //{
        //    return HttpUtility.HtmlDecode(str);
        //}

        public static int CnLength(this string str)
        {
            return Encoding.Default.GetBytes(str).Length;
        }

        public static string ReplaceWith(this string value, string regexPattern, string replaceValue)
        {
            return ReplaceWith(value, regexPattern, replaceValue, RegexOptions.None);
        }

        public static string ReplaceWith(this string value, string regexPattern, string replaceValue, RegexOptions options)
        {
            return Regex.Replace(value, regexPattern, replaceValue, options);
        }

        public static string ReplaceWith(this string value, string regexPattern, MatchEvaluator evaluator)
        {
            return ReplaceWith(value, regexPattern, RegexOptions.None, evaluator);
        }

        public static string ReplaceWith(this string value, string regexPattern, RegexOptions options, MatchEvaluator evaluator)
        {
            return Regex.Replace(value, regexPattern, evaluator, options);
        }

        public static string ReplaceWith(this string value, string regexPattern, string ReplaceString, bool IsCaseInsensetive)
        {
            return Regex.Replace(value, regexPattern, ReplaceString, IsCaseInsensetive ? RegexOptions.IgnoreCase : RegexOptions.None);
        }

        public static string Replace(this string RegValue, string regStart, string regEnd)
        {
            string s = RegValue;
            if (RegValue != "" && RegValue != null)
            {
                if (regStart != "" && regStart != null) { s = s.Replace(regStart, ""); }
                if (regEnd != "" && regEnd != null) { s = s.Replace(regEnd, ""); }
            }
            return s;
        }

        public static MatchCollection GetMatches(this string value, string regexPattern)
        {
            return GetMatches(value, regexPattern, RegexOptions.None);
        }
        public static MatchCollection GetMatches(this string value, string regexPattern, RegexOptions options)
        {
            return Regex.Matches(value, regexPattern, options);
        }
        public static MatchCollection FindBetween(this string s, string startString, string endString)
        {
            return s.FindBetween(startString, endString, true);
        }
        public static MatchCollection FindBetween(this string s, string startString, string endString, bool recursive)
        {
            MatchCollection matches;

            startString = Regex.Escape(startString);
            endString = Regex.Escape(endString);

            Regex regex = new Regex("(?<=" + startString + ").*(?=" + endString + ")");

            matches = regex.Matches(s);

            if (!recursive) return matches;

            if (matches.Count > 0)
            {
                if (matches[0].ToString().IndexOf(Regex.Unescape(startString)) > -1)
                {
                    s = matches[0].ToString() + Regex.Unescape(endString);
                    return s.FindBetween(Regex.Unescape(startString), Regex.Unescape(endString));
                }
                else
                {
                    return matches;
                }
            }
            else
            {
                return matches;
            }
        }

        public static IEnumerable<string> GetMatchingValues(this string value, string regexPattern)
        {
            return GetMatchingValues(value, regexPattern, RegexOptions.None);
        }
        public static IEnumerable<string> GetMatchingValues(this string value, string regexPattern, RegexOptions options)
        {
            foreach (Match match in GetMatches(value, regexPattern, options))
            {
                if (match.Success) yield return match.Value;
            }
        }
        public static IList<string> GetMatchingValues(this string value, string regexPattern, string rep1, string rep2)
        {
            IList<string> txtTextArr = new List<string>();
            string MatchVale = "";
            foreach (Match m in Regex.Matches(value, regexPattern))
            {
                MatchVale = m.Value.Trim().Replace(rep1, "").Replace(rep2, "");
                txtTextArr.Add(MatchVale);
            }
            return txtTextArr;
        }

        public static string[] Split(this string value, string regexPattern, RegexOptions options)
        {
            return Regex.Split(value, regexPattern, options);
        }
        public static string[] Split(this string value, string regexPattern)
        {
            return value.Split(regexPattern, RegexOptions.None);
        }

        public static XmlDocument ToXmlDOM(this string xml)
        {
            var document = new XmlDocument();
            document.LoadXml(xml);
            return document;
        }
        public static XPathNavigator ToXPath(this string xml)
        {
            var document = new XPathDocument(new StringReader(xml));
            return document.CreateNavigator();
        }

        public static string Left(this string @string, int length)
        {
            if (length <= 0 || @string.Length == 0) return string.Empty;
            if (@string.Length <= length) return @string;
            return @string.Substring(0, length);
        }
        public static string Right(this string @string, int length)
        {
            if (length <= 0 || @string.Length == 0) return string.Empty;
            if (@string.Length <= length) return @string;
            return @string.Substring(@string.Length - length, length);
        }

        public static T CreateType<T>(this string typeName, params object[] args)
        {
            Type type = Type.GetType(typeName, true, true);
            return (T)Activator.CreateInstance(type, args);
        }
        public static T ToEnum<T>(this string value)
        {
            return ToEnum<T>(value, false);
        }
        public static T ToEnum<T>(this string value, bool ignorecase)
        {
            if (value == null) throw new ArgumentNullException("Value");
            value = value.Trim();
            if (value.Length == 0) throw new ArgumentNullException("Must specify valid information for parsing in the string.", "value");
            Type t = typeof(T);
            if (!t.IsEnum) throw new ArgumentException("Type provided must be an Enum.", "T");
            return (T)Enum.Parse(t, value, ignorecase);
        }

        public static int CharacterCount(this string value, char character)
        {
            int intReturnValue = 0;

            for (int intCharacter = 0; intCharacter <= (value.Length - 1); intCharacter++)
            {
                if (value.Substring(intCharacter, 1) == character.ToString()) intReturnValue += 1;
            }

            return intReturnValue;
        }

        public static string ForcePrefix(this string s, string prefix)
        {
            string result = s;
            if (!result.StartsWith(prefix)) result = prefix + result;
            return result;
        }
        public static string ForceSuffix(this string s, string suffix)
        {
            string result = s;
            if (!result.EndsWith(suffix)) result += suffix;
            return result;
        }
        public static string RemovePrefix(this string s, string prefix)
        {
            return Regex.Replace(s, "^" + prefix, System.String.Empty, RegexOptions.IgnoreCase);
        }
        public static string RemoveSuffix(this string s, string suffix)
        {
            return Regex.Replace(s, suffix + "$", System.String.Empty, RegexOptions.IgnoreCase);
        }

        public static string PadLeft(this string s, string pad)
        {
            return s.PadLeft(pad, s.Length + pad.Length, false);
        }
        public static string PadLeft(this string s, string pad, int totalWidth, bool cutOff)
        {
            if (s.Length >= totalWidth) return s;

            int padCount = pad.Length;

            string paddedString = s;

            while (paddedString.Length < totalWidth) paddedString += pad;

            if (cutOff) paddedString = paddedString.Substring(0, totalWidth);

            return paddedString;
        }
        public static string PadRight(this string s, string pad)
        {
            return PadRight(s, pad, s.Length + pad.Length, false);
        }
        public static string PadRight(this string s, string pad, int length, bool cutOff)
        {
            if (s.Length >= length) return s;

            string paddedString = string.Empty;

            while (paddedString.Length < length - s.Length) paddedString += pad;

            if (cutOff) paddedString = paddedString.Substring(0, length - s.Length);

            paddedString += s;

            return paddedString;
        }

        public static bool ContainsArray(this string value, params string[] keywords)
        {
            return keywords.All((s) => value.Contains(s));
        }
        public static Nullable<T> ToNullable<T>(this string s) where T : struct
        {
            T? result = null;
            if (!s.Trim().IsNullEmpty())
            {
                TypeConverter converter = TypeDescriptor.GetConverter(typeof(T?));
                result = (T?)converter.ConvertFrom(s);
            }
            return result;
        }

        public static List<string> GetLines(this string text)
        {
            return text.Split(new[] { Environment.NewLine }, StringSplitOptions.None).ToList();
        }

        public static bool IsMatch(this string str, string op)
        {
            if (str.Equals(String.Empty) || str == null) return false;
            Regex re = new Regex(op, RegexOptions.IgnoreCase);
            return re.IsMatch(str);
        }
        public static bool IsIP(this string input)
        {
            return input.IsMatch(@"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$"); //@"^(([01]?[\d]{1,2})|(2[0-4][\d])|(25[0-5]))(\.(([01]?[\d]{1,2})|(2[0-4][\d])|(25[0-5]))){3}$";
        }
        public static bool IsIPSect(this string ip)
        {
            return ip.IsMatch(@"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){2}((2[0-4]\d|25[0-5]|[01]?\d\d?|\*)\.)(2[0-4]\d|25[0-5]|[01]?\d\d?|\*)$");
        }
        public static bool IsNumber(this string strNumber)
        {
            string pet = @"^([0-9])[0-9]*(\.\w*)?$";
            return strNumber.IsMatch(pet);
        }
        public static bool IsDouble(this string input)
        {
            string pet = @"^[0-9]*[1-9][0-9]*$";//@"^\d{1,}$"//整数校验常量//@"^-?(0|\d+)(\.\d+)?$"//数值校验常量 
            return input.IsMatch(pet);
        }
        public static bool IsInt(this string input)
        {
            string pet = @"^[0-9]*$"; //@"^([0-9])[0-9]*(\.\w*)?$";
            return input.IsMatch(pet);
        }
        public static bool IsNumberArray(this string[] strNumber)
        {
            if (strNumber == null) return false;
            if (strNumber.Length < 1) return false;
            foreach (string id in strNumber)
                if (!id.IsNumber()) return false;
            return true;
        }
        public static bool IsEmail(this string input)
        {
            string pet = @"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$";//@"^\w+((-\w+)|(\.\w+))*\@\w+((\.|-)\w+)*\.\w+$";
            return input.IsMatch(pet);
        }
        public static bool IsUrl(this string input)
        {
            string pet = @"^(http|https)\://([a-zA-Z0-9\.\-]+(\:[a-zA-Z0-9\.&%\$\-]+)*@)*((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|localhost|([a-zA-Z0-9\-]+\.)*[a-zA-Z0-9\-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{1,10}))(\:[0-9]+)*(/($|[a-zA-Z0-9\.\,\?\'\\\+&%\$#\=~_\-]+))*$";//@"^http://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?";
            return input.IsMatch(pet);
        }
        public static bool IsZip(this string input)
        {
            return input.IsMatch(@"\d{6}");
        }
        public static bool IsSSN(this string input)
        {
            string pet = @"\d{18}|\d{15}";
            return input.IsMatch(pet);
        }
        public static bool IsSafeSqlString(this string str)
        {
            return !Regex.IsMatch(str, @"[-|;|,|\/|\(|\)|\[|\]|\}|\{|%|@|\*|!|\']");
        }
        public static bool IsDateTime(this string input)
        {
            //string pet = @"^(?:(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00)))(\/|-|\.)(?:0?2\1(?:29))$)|(?:(?:1[6-9]|[2-9]\d)?\d{2})(\/|-|\.)(?:(?:(?:0?[13578]|1[02])\2(?:31))|(?:(?:0?[1,3-9]|1[0-2])\2(29|30))|(?:(?:0?[1-9])|(?:1[0-2]))\2(?:0?[1-9]|1\d|2[0-8]))$";
            string pet = @"^(?=\d)(?:(?!(?:1582(?:\.|-|\/)10(?:\.|-|\/)(?:0?[5-9]|1[0-4]))|(?:1752(?:\.|-|\/)0?9(?:\.|-|\/)(?:0?[3-9]|1[0-3])))(?=(?:(?!000[04]|(?:(?:1[^0-6]|[2468][^048]|[3579][^26])00))(?:(?:\d\d)(?:[02468][048]|[13579][26]))\D0?2\D29)|(?:\d{4}\D(?!(?:0?[2469]|11)\D31)(?!0?2(?:\.|-|\/)(?:29|30))))(\d{4})([-\/.])(0?\d|1[012])\2((?!00)[012]?\d|3[01])(?:$|(?=\x20\d)\x20))?((?:(?:0?[1-9]|1[012])(?::[0-5]\d){0,2}(?:\x20[aApP][mM]))|(?:[01]?\d|2[0-3])(?::[0-5]\d){1,2})?$";
            return input.IsMatch(pet);
        }
        public static bool IsDateTime2(this string DateTimeStr)
        {
            try { DateTime _dt = DateTime.Parse(DateTimeStr); return true; }
            catch { return false; }
        }
        public static bool IsDate(this string DateStr)
        {
            try { DateTime _dt = DateTime.Parse(DateStr); return true; }
            catch { return false; }
        }
        public static bool IsTime(this string TimeStr)
        {
            return TimeStr.IsMatch(@"^([0-1]\\d|2[0-3]):[0-5]\\d:[0-5]\\d$");//^((([0-1]?[0-9])|(2[0-3])):([0-5]?[0-9])(:[0-5]?[0-9])?)$
        }
        public static bool IsAlphaNumeric(this string input)
        {
            return input.IsMatch(@"[^a-zA-Z0-9]");
        }
        public static bool IsTelepone(this string input)
        {
            return input.IsMatch(@"^[+]{0,1}(\d){1,3}[ ]?([-]?((\d)|[ ]){1,12})+$");//："^(\(\d{3,4}-)|\d{3.4}-)?\d{7,8}$
        }
        public static bool IsMobile(this string input)
        {
            return input.IsMatch(@"^[+]{0,1}(\d){1,3}[ ]?([-]?((\d)|[ ]){1,12})+$");
        }

        public static bool IsInArray(this string stringarray, string str)
        {
            return stringarray.Split(",").IsInArray(str, false);
        }
        public static bool IsInArray(this string stringarray, string str, string strsplit)
        {
            return stringarray.Split(strsplit).IsInArray(str, false);
        }
        public static bool IsInArray(this string stringarray, string str, string strsplit, bool caseInsensetive)
        {
            return stringarray.Split(strsplit).IsInArray(str, caseInsensetive);
        }
        public static bool IsBase64String(this string str)
        {
            return Regex.IsMatch(str, @"[A-Za-z0-9\+\/\=]");
        }
        public static bool IsYear(this string input)
        {
            return Regex.IsMatch(input, @"^(19\d\d)|(200\d)$");
        }

        public static bool IsImgFileName(this string filename)
        {
            filename = filename.Trim();
            if (filename.EndsWith(".") || (filename.IndexOf(".") == -1)) return false;
            string str = filename.Substring(filename.LastIndexOf(".") + 1).ToLower();
            if (((str != "jpg") && (str != "jpeg")) && ((str != "png") && (str != "bmp"))) return (str == "gif");
            return true;
        }

        public static bool IsGuid(this string s)
        {
            if (s.IsNullEmpty()) return false;
            Regex format = new Regex("^[A-Fa-f0-9]{32}$|" +
                "^({|\\()?[A-Fa-f0-9]{8}-([A-Fa-f0-9]{4}-){3}[A-Fa-f0-9]{12}(}|\\))?$|" +
                "^({)?[0xA-Fa-f0-9]{3,10}(, {0,1}[0xA-Fa-f0-9]{3,6}){2},{0,1}({)([0xA-Fa-f0-9]{3,4}, {0,1}){7}[0xA-Fa-f0-9]{3,4}(}})$");
            Match match = format.Match(s);
            return match.Success;
        }

        //public static string GetMapPath(this string strPath)
        //{
        //    if (HttpContext.Current != null)
        //        return HttpContext.Current.Server.MapPath(strPath);
        //    else
        //        return System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, strPath);
        //}

        public static Guid ToGuid(this string target)
        {
            if ((!target.IsNullEmpty()) && (target.Trim().Length == 22))
            {
                string encoded = string.Concat(target.Trim().Replace("-", "+").Replace("_", "/"), "==");
                byte[] base64 = Convert.FromBase64String(encoded);
                return new Guid(base64);
            }
            return Guid.Empty;
        }


        /// <summary>
        /// StringFormat扩展
        /// </summary>
        /// <param name="Str"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public static string FormatWith(this String Str, params object[] param)
        {
            if (Str.IsNullOrWhiteSpace())
            {
                string str = string.Empty;

                param.Each(s => str += s + "");

                return str;
            }

            return String.Format(Str, param);
        }


        #endregion

        #region 字符串--身份证验证扩展

        /// <summary>  
        /// 验证身份证合理性  
        /// </summary>  
        /// <param name="Id"></param>  
        /// <returns></returns>  
        public static bool IsValidIDCard(this string idNumber)
        {
            if (idNumber.Length == 18)
            {
                bool check = CheckIDCard18(idNumber);
                return check;
            }
            else if (idNumber.Length == 15)
            {
                bool check = CheckIDCard15(idNumber);
                return check;
            }
            else
            {
                return false;
            }
        }


        /// <summary>  
        /// 18位身份证号码验证  
        /// </summary>  
        static bool CheckIDCard18(string idNumber)
        {
            long n = 0;
            if (long.TryParse(idNumber.Remove(17), out n) == false
                || n < Math.Pow(10, 16) || long.TryParse(idNumber.Replace('x', '0').Replace('X', '0'), out n) == false)
            {
                return false;//数字验证  
            }
            string address = "11x22x35x44x53x12x23x36x45x54x13x31x37x46x61x14x32x41x50x62x15x33x42x51x63x21x34x43x52x64x65x71x81x82x91";
            if (address.IndexOf(idNumber.Remove(2)) == -1)
            {
                return false;//省份验证  
            }
            string birth = idNumber.Substring(6, 8).Insert(6, "-").Insert(4, "-");
            DateTime time = new DateTime();
            if (DateTime.TryParse(birth, out time) == false)
            {
                return false;//生日验证  
            }
            string[] arrVarifyCode = ("1,0,x,9,8,7,6,5,4,3,2").Split(',');
            string[] Wi = ("7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2").Split(',');
            char[] Ai = idNumber.Remove(17).ToCharArray();
            int sum = 0;
            for (int i = 0; i < 17; i++)
            {
                sum += int.Parse(Wi[i]) * int.Parse(Ai[i].ToString());
            }
            int y = -1;
            Math.DivRem(sum, 11, out y);
            if (arrVarifyCode[y] != idNumber.Substring(17, 1).ToLower())
            {
                return false;//校验码验证  
            }
            return true;//符合GB11643-1999标准  
        }


        /// <summary>  
        /// 15位身份证号码验证  
        /// </summary>  
        static bool CheckIDCard15(string idNumber)
        {
            long n = 0;
            if (long.TryParse(idNumber, out n) == false || n < Math.Pow(10, 14))
            {
                return false;//数字验证  
            }
            string address = "11x22x35x44x53x12x23x36x45x54x13x31x37x46x61x14x32x41x50x62x15x33x42x51x63x21x34x43x52x64x65x71x81x82x91";
            if (address.IndexOf(idNumber.Remove(2)) == -1)
            {
                return false;//省份验证  
            }
            string birth = idNumber.Substring(6, 6).Insert(4, "-").Insert(2, "-");
            DateTime time = new DateTime();
            if (DateTime.TryParse(birth, out time) == false)
            {
                return false;//生日验证  
            }
            return true;
        }
        #endregion

        #region Baase64编码与解码
        /// <summary>
        /// base64编码
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static string Base64Encode(this string s)
        {
            return Convert.ToBase64String(Encoding.UTF8.GetBytes(s));
        }

        /// <summary>
        /// base64解码
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static string Base64Decode(this string s)
        {
            return Encoding.UTF8.GetString(Convert.FromBase64String(s));
        } 
        #endregion

        #region 数组扩展
        public static bool IsNullEmpty(this Array array) { return array == null || array.Length == 0; }
        public static bool IsNullEmpty(this ArrayList list) { return (list == null) || (list.Count == 0); }

        public static int GetInArrayID(this string[] stringArray, string strSearch, bool caseInsensetive) {
            for (int i = 0; i < stringArray.Length; i++) {
                if (caseInsensetive) {
                    if(strSearch.ToLower() == stringArray[i].ToLower()) return i;
                } else {
                    if(strSearch == stringArray[i]) return i;
                }                
            }
            return -1;
        }
        public static int GetInArrayID(this string[] stringArray, string strSearch) {
            return GetInArrayID(stringArray, strSearch, true);
        }

        public static string ToDelimitedString<T>(this T[] array, string format, string delimiter) {
            if (array == null || array.Length == 0) return string.Empty;
            if (format.IsNullEmpty()) format = "{0}";

            StringBuilder builder = new StringBuilder();
            for (int index = 0; index < array.Length; ++index) {
                if (index != 0) builder.Append(delimiter);
                builder.AppendFormat(format, array[index]);
            }

            return builder.ToString();
        }
        public static T[] RemoveDuplicates<T>(this T[] array) {
            ArrayList al = new ArrayList();
            for (int i = 0; i < array.Length; i++) {
                if (!al.Contains(array[i])) al.Add(array[i]);
            }
            return (T[])al.ToArray(typeof(T));
        }
        public static T[] Slice<T>(this T[] array, int start, int end) {
            if (start >= array.Length) { start = 0; end = 0; }
            if (end < 0) end = array.Length - start - end;
            if (end <= start) end = start;
            if (end >= array.Length) end = array.Length-1;
            int len = end - start + 1;
            T[] res = new T[len];
            for (int i = 0; i < len; i++) res[i] = array[i + start];
            return res;
        }
        public static string Join<T>(this T[] array, string splitStr) {
            StringBuilder sb = new StringBuilder();
            foreach(T info in array) {
                sb.AppendFormat("{0}{1}", info.ToString(), splitStr);
            }
            return sb.ToString().Left(sb.Length - splitStr.Length);
        }

        public static void Action<T>(this T[] inArray, Action<T, Int32> inAction) {
            for (int i0 = 0; i0 < inArray.GetLength(0); i0++) {
                inAction(inArray[i0], i0);
            }
        }
        public static void Action<T>(this T[,] inArray, Action<T, Int32, Int32> inAction) {
            for (int i0 = 0; i0 < inArray.GetLength(0); i0++) {
                for (int i1 = 0; i1 < inArray.GetLength(1); i1++) inAction(inArray[i0, i1], i0, i1);
            }
        }
        public static void Action<T>(this T[,,] inArray, Action<T, Int32, Int32, Int32> inAction) {
            for (int i0 = 0; i0 < inArray.GetLength(0); i0++) {
                for (int i1 = 0; i1 < inArray.GetLength(1); i1++) {
                    for (int i2 = 0; i2 < inArray.GetLength(2); i2++) inAction(inArray[i0, i1, i2], i0, i1, i2);
                }
            }
        }
        public static void Action<T>(this T[,] inArray, Int32 inDimension, Int32 inIndex, Action<T, Int32> inAction) {
            if (inDimension == 0) {
                for (int i = 0; i < inArray.GetLength(1); i++) inAction(inArray[inIndex, i], i);
            } else if (inDimension == 1) {
                for (int i = 0; i < inArray.GetLength(0); i++) inAction(inArray[i, inIndex], i);
            } else {
                throw new ArgumentException("inDimension must be zero or one");
            }
        }
        public static void Action<T>(this T[,,] inArray, Int32 inDimension, Int32 inIndex, Action<T, Int32, Int32> inAction) {
            if (inDimension == 0) {
                for (int i0 = 0; i0 < inArray.GetLength(1); i0++) {
                    for (int i1 = 0; i1 < inArray.GetLength(2); i1++) inAction(inArray[inIndex, i0, i1], i0, i1);
                }
            } else if (inDimension == 1) {
                for (int i0 = 0; i0 < inArray.GetLength(0); i0++){
                    for (int i1 = 0; i1 < inArray.GetLength(2); i1++) inAction(inArray[i0, inIndex, i1], i0, i1);
                }
            } else if (inDimension == 2) {
                for (int i0 = 0; i0 < inArray.GetLength(0); i0++){
                    for (int i1 = 0; i1 < inArray.GetLength(1); i1++) inAction(inArray[i0, i1, inIndex], i0, i1);
                }
            } else {
                throw new ArgumentException("inDimension must be zero or one or two");
            }
        }

        public static bool ToFile(this byte[] bytes, string fileName, FileMode fileMode) {
            bool returnValue = true;
            FileAccess fileAccess = FileAccess.ReadWrite;
            if (fileMode == FileMode.Append) fileAccess = FileAccess.Write;
            FileStream fs = new FileStream(fileName, fileMode, fileAccess);
            BinaryWriter bw = new BinaryWriter(fs);
            try { bw.Write(bytes); } catch (Exception) { returnValue = false; } finally { fs.Close(); bw.Close(); }
            return returnValue;
        }

        public static T Deserialize<T>(this byte[] data) where T : class {
            var formatter = new BinaryFormatter();
            using (MemoryStream ms = new MemoryStream(data)) return formatter.Deserialize(ms) as T;
        }

        public static bool IsInArray(this string[] stringArray, string strSearch, bool caseInsensetive) {
            return stringArray.GetInArrayID(strSearch, caseInsensetive) >= 0;
        }

        public static bool IsInArray(this string[] stringarray, string str) {
            return stringarray.IsInArray(str, false);
        }

        public static bool IsInIPArray(this string[] iparray, string ip) {
            string[] userip = ip.Split(@".");
            for (int ipIndex = 0; ipIndex < iparray.Length; ipIndex++) {
                string[] tmpip = iparray[ipIndex].Split(@".");
                int r = 0;
                for (int i = 0; i < tmpip.Length; i++) {
                    if (tmpip[i] == "*") return true;
                    if (userip.Length > i) {
                        if (tmpip[i] == userip[i]) r ++; else break;
                    } else break;
                }
                if (r == 4) return true;
            }
            return false;
        }

        /// <summary>
        /// 扩展数据方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="condition"></param>
        /// <returns></returns>
        public static bool Contains<T>(this T[] t, Predicate<T> condition)
        {
            bool IsExisted = false;

            foreach (T item in t)
            {
                if (condition(item))
                {
                    IsExisted = true;
                    break;
                }
            }

            return IsExisted;
        }

        #endregion

        #region 集合扩展
        /// <summary>
        /// 扩展foreach循环
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="enumerable"></param>
        /// <param name="action"></param>
        public static void Each<T>(this IEnumerable<T> enumerable, Action<T> action)
        {
            if (action == null) return;

            foreach (var item in enumerable)
                action(item);
        }

        public static List<TSource> ToPage<TSource>(this IEnumerable<TSource> varlist, int pageIndex, int pageSize, out int totalRecords)
        {
            totalRecords = varlist.Count();
            return varlist.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
        }

        public static IEnumerable<T> ForEach<T>(this IEnumerable<T> source, Action<T> action)
        {
            foreach (T element in source)
            {
                action(element);
                yield return element;
            }
        }

        public static IEnumerable<T> ForEach<T>(this IEnumerable<T> items, Action<T> odd, Action<T> even)
        {
            bool isOdd = true;
            return ForEach(items, item =>
            {
                if (isOdd) odd(item); else even(item);
                isOdd = !isOdd;
            });
        }

        public static IEnumerable<T> MergeWith<T>(this IEnumerable<T> target, params IEnumerable<T>[] data)
        {
            List<T> list = new List<T>(target);
            data.ForEach(array => list.AddRange(array));
            return list;
        }

        public static IEnumerable<T> With<T>(this IEnumerable<T> source, T item)
        {
            foreach (T t in source) yield return t;
            yield return item;
        }
        #endregion

        #region 实体转换
        /// <summary>
        /// 对可空类型进行判断转换(*要不然会报错)
        /// </summary>
        /// <param name="value">DataReader字段的值</param>
        /// <param name="conversionType">该字段的类型</param>
        /// <returns></returns>
        private static object CheckType(object value, Type conversionType)
        {
            if (conversionType.IsGenericType && conversionType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
            {
                if (value == null)
                    return null;
                System.ComponentModel.NullableConverter nullableConverter = new System.ComponentModel.NullableConverter(conversionType);
                conversionType = nullableConverter.UnderlyingType;
            }
            return Convert.ChangeType(value, conversionType);
        }

        /// <summary>
        /// 判断指定对象是否是有效值
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        private static bool IsNullOrDBNull(this object obj)
        {
            return (obj == null || (obj is DBNull)) ? true : false;
        }

        /// <summary>
        /// DataRow转实体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="table"></param>
        /// <returns></returns>
        public static T GetEntity<T>(this DataRow row) where T : new()
        {
            T entity = new T();
            foreach (var item in entity.GetType().GetProperties())
            {
                if (row.Table.Columns.Contains(item.Name))
                {
                    if (DBNull.Value != row[item.Name])
                    {
                        item.SetValue(entity, Convert.ChangeType(row[item.Name], item.PropertyType), null);
                    }

                }
            }
            return entity;
        }

        /// <summary>
        /// DataRow集合转实体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="table"></param>
        /// <returns></returns>
        public static List<T> GetEntitys<T>(this DataRow[] Rows) where T : new()
        {
            List<T> entities = new List<T>();
            foreach (DataRow row in Rows)
            {
                T entity = new T();
                foreach (var item in entity.GetType().GetProperties())
                {
                    if (row.Table.Columns.Contains(item.Name) && DBNull.Value != row[item.Name])
                    {
                        item.SetValue(entity, Convert.ChangeType(row[item.Name], item.PropertyType), null);
                    }
                }
                entities.Add(entity);
            }
            return entities;
        }

        /// <summary>
        /// 表转实体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="table"></param>
        /// <returns></returns>
        public static T GetEntity<T>(this DataTable table) where T : new()
        {
            T entity = new T();
            foreach (DataRow row in table.Rows)
            {
                foreach (var item in entity.GetType().GetProperties())
                {
                    if (row.Table.Columns.Contains(item.Name))
                    {
                        if (DBNull.Value != row[item.Name])
                        {
                            item.SetValue(entity, Convert.ChangeType(row[item.Name], item.PropertyType), null);
                        }

                    }
                }
            }

            return entity;
        }

        /// <summary>
        /// 表转实体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="table"></param>
        /// <returns></returns>
        public static T GetEntity<T>(this IDataReader reader) where T : new()
        {
            using (reader)
            {
                T entity = new T();

                //获取传入的数据类型
                Type modelType = typeof(T);

                //遍历DataReader对象
                while (reader.Read())
                {
                    //使用与指定参数匹配最高的构造函数，来创建指定类型的实例
                    entity = Activator.CreateInstance<T>();
                    for (int i = 0; i < reader.FieldCount; i++)
                    {
                        //判断字段值是否为空或不存在的值
                        if (!IsNullOrDBNull(reader[i]))
                        {
                            //匹配字段名
                            PropertyInfo pi = modelType.GetProperty(reader.GetName(i), BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
                            if (pi != null)
                            {
                                //绑定实体对象中同名的字段  
                                pi.SetValue(entity, CheckType(reader[i], pi.PropertyType), null);
                            }
                        }
                    }
                    break;
                }
                return entity;
            }
        }

        /// <summary>
        /// 表转集合
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="table"></param>
        /// <returns></returns>
        public static List<T> GetEntities<T>(this DataTable table) where T : new()
        {
            List<T> entities = new List<T>();
            foreach (DataRow row in table.Rows)
            {
                T entity = new T();
                foreach (var item in entity.GetType().GetProperties())
                {
                    if (row.Table.Columns.Contains(item.Name) && DBNull.Value != row[item.Name])
                    {
                        item.SetValue(entity, Convert.ChangeType(row[item.Name], item.PropertyType), null);
                    }
                }
                entities.Add(entity);
            }
            return entities;
        }


        /// <summary>
        /// DataReader转泛型
        /// </summary>
        /// <typeparam name="T">传入的实体类</typeparam>
        /// <param name="objReader">DataReader对象</param>
        /// <returns></returns>
        public static IList<T> ReaderToList<T>(this IDataReader objReader)
        {
            using (objReader)
            {
                List<T> list = new List<T>();

                //获取传入的数据类型
                Type modelType = typeof(T);

                //遍历DataReader对象
                while (objReader.Read())
                {
                    //使用与指定参数匹配最高的构造函数，来创建指定类型的实例
                    T model = Activator.CreateInstance<T>();
                    for (int i = 0; i < objReader.FieldCount; i++)
                    {
                        //判断字段值是否为空或不存在的值
                        if (!IsNullOrDBNull(objReader[i]))
                        {
                            //匹配字段名
                            PropertyInfo pi = modelType.GetProperty(objReader.GetName(i), BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
                            if (pi != null)
                            {
                                //绑定实体对象中同名的字段  
                                pi.SetValue(model, CheckType(objReader[i], pi.PropertyType), null);
                            }
                        }
                    }
                    list.Add(model);
                }
                return list;
            }
        }

        public static T Get<T>(this IDataReader reader, string field, T defaultValue)
        {
            var value = reader[field];
            if (value == DBNull.Value) return defaultValue;

            return value.ConvertTo<T>(defaultValue);
        }

        /// <summary>
        /// DataReader转模型
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="objReader"></param>
        /// <returns></returns>
        public static T ReaderToModel<T>(this IDataReader objReader)
        {

            using (objReader)
            {
                if (objReader.Read())
                {
                    Type modelType = typeof(T);
                    int count = objReader.FieldCount;
                    T model = Activator.CreateInstance<T>();
                    for (int i = 0; i < count; i++)
                    {
                        if (!IsNullOrDBNull(objReader[i]))
                        {
                            PropertyInfo pi = modelType.GetProperty(objReader.GetName(i), BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
                            if (pi != null)
                            {
                                pi.SetValue(model, CheckType(objReader[i], pi.PropertyType), null);
                            }
                        }
                    }
                    return model;
                }
            }
            return default(T);
        }
        #endregion

        #region TreeDataExtensions

        public static IEnumerable<T> GetDescendants<T>(this T root, Func<T, IEnumerable<T>> childSelector, Predicate<T> filter = null)
        {
            foreach (T t in childSelector(root))
            {
                if (filter == null || filter(t))
                    yield return t;
                foreach (T child in GetDescendants((T)t, childSelector, filter))
                    yield return child;
            }
        }

        public static IEnumerable<T> GetDescendants<TRoot, T>(this TRoot root, Func<TRoot, IEnumerable<T>> rootChildSelector, Func<T, IEnumerable<T>> childSelector, Predicate<T> filter = null)
        {
            foreach (T t in rootChildSelector(root))
            {
                if (filter == null || filter(t))
                    yield return t;
                foreach (T child in GetDescendants(t, childSelector, filter))
                    yield return child;
            }
        }

        #endregion

        #region 枚举扩展
        /// <summary>
        /// 从枚举中获取Description
        /// 说明：
        /// 单元测试-->通过
        /// </summary>
        /// <param name="enumName">需要获取枚举描述的枚举</param>
        /// <returns>描述内容</returns>
        public static string GetDescription(this Enum enumName)
        {
            string _description = string.Empty;
            FieldInfo _fieldInfo = enumName.GetType().GetField(enumName.ToString());
            DescriptionAttribute[] _attributes = _fieldInfo.GetDescriptAttr();
            if (_attributes != null && _attributes.Length > 0)
                _description = _attributes[0].Description;
            else
                _description = enumName.ToString();
            return _description;
        }

        /// <summary>
        /// 获取字段Description
        /// </summary>
        /// <param name="fieldInfo">FieldInfo</param>
        /// <returns>DescriptionAttribute[] </returns>
        public static DescriptionAttribute[] GetDescriptAttr(this FieldInfo fieldInfo)
        {
            if (fieldInfo != null)
            {
                return (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
            }
            return null;
        }

        /// <summary>
        /// 根据Description获取枚举
        /// 说明：
        /// 单元测试-->通过
        /// </summary>
        /// <typeparam name="T">枚举类型</typeparam>
        /// <param name="description">枚举描述</param>
        /// <returns>枚举</returns>
        public static T GetEnumName<T>(this string description)
        {
            Type _type = typeof(T);
            foreach (FieldInfo field in _type.GetFields())
            {
                DescriptionAttribute[] _curDesc = field.GetDescriptAttr();
                if (_curDesc != null && _curDesc.Length > 0)
                {
                    if (_curDesc[0].Description == description)
                        return (T)field.GetValue(null);
                }
                else
                {
                    if (field.Name == description)
                        return (T)field.GetValue(null);
                }
            }
            throw new ArgumentException(string.Format("{0} 未能找到对应的枚举.", description), "Description");
        }

        #endregion

        #region DictionaryExtensions
        /// <summary>
        /// 尝试将键和值添加到字典中：如果不存在，才添加；存在，不添加也不抛导常
        /// </summary>
        public static Dictionary<TKey, TValue> TryAdd<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key, TValue value)
        {
            if (dict.ContainsKey(key) == false) dict.Add(key, value);
            return dict;
        }

        /// <summary>
        /// 将键和值添加或替换到字典中：如果不存在，则添加；存在，则替换
        /// </summary>
        public static Dictionary<TKey, TValue> AddOrReplace<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key, TValue value)
        {
            dict[key] = value;
            return dict;
        }

        /// <summary>
        /// 获取与指定的键相关联的值，如果没有则返回输入的默认值
        /// </summary>
        public static TValue GetValue<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key, TValue defaultValue = default(TValue))
        {
            return dict.ContainsKey(key) ? dict[key] : defaultValue;
        }

        /// <summary>
        /// 向字典中批量添加键值对
        /// </summary>
        /// <param name="replaceExisted">如果已存在，是否替换</param>
        public static Dictionary<TKey, TValue> AddRange<TKey, TValue>(this Dictionary<TKey, TValue> dict, IEnumerable<KeyValuePair<TKey, TValue>> values, bool replaceExisted)
        {
            foreach (var item in values)
            {
                if (dict.ContainsKey(item.Key) == false || replaceExisted)
                    dict[item.Key] = item.Value;
            }
            return dict;
        }
        #endregion

        #region 日期扩展
        public static string ToyyyyMMddHHmmss(this DateTime dt)
        {
            return dt.ToString("yyyy-MM-dd HH:mm:ss");
        }

        /// <summary>
        /// 将Unix时间戳转换为DateTime类型时间
        /// </summary>
        /// <param name="d">double 型数字</param>
        /// <returns>DateTime</returns>
        public static System.DateTime ConvertIntDateTime(this double d)
        {
            System.DateTime time = System.DateTime.MinValue;
            System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
            time = startTime.AddMilliseconds(d);
            return time;
        }

        /// <summary>
        /// 将c# DateTime时间格式转换为Unix时间戳格式
        /// </summary>
        /// <param name="time">时间</param>
        /// <returns>long</returns>
        public static long ConvertDateTimeInt(this System.DateTime time)
        {
            //double intResult = 0;
            System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1, 0, 0, 0, 0));
            //intResult = (time- startTime).TotalMilliseconds;
            long t = (time.Ticks - startTime.Ticks) / 10000; //除10000调整为13位
            return t;
        }
        #endregion

        //#region 加解密扩展

        ///// <summary>
        ///// AES加密
        ///// </summary>
        ///// <param name="str"></param>
        ///// <returns></returns>
        //public static string AesEncrypt(this string str, string key = "", string iv = "")
        //{
        //    if (string.IsNullOrWhiteSpace(str)) return string.Empty;

        //    return Aes.Encrypt(str, key, iv);
        //}

        ///// <summary>
        ///// AES解密
        ///// </summary>
        ///// <param name="str"></param>
        ///// <returns></returns>
        //public static string AesDecrypt(this string str, string key = "", string iv = "")
        //{
        //    if (string.IsNullOrWhiteSpace(str)) return string.Empty;

        //    return Aes.Decrypt(str, key, iv);
        //}

        ///// <summary>
        ///// DES加密
        ///// </summary>
        ///// <param name="str"></param>
        ///// <returns></returns>
        //public static string DesEncrypt(this string str,string key)
        //{
        //    if (string.IsNullOrWhiteSpace(str)) return string.Empty;

        //    return DES.Encrypt(str,key);
        //}

        ///// <summary>
        ///// DES解密
        ///// </summary>
        ///// <param name="str"></param>
        ///// <returns></returns>
        //public static string DesDecrypt(this string str, string key)
        //{
        //    if (string.IsNullOrWhiteSpace(str)) return string.Empty;

        //    return DES.Decrypt(str, key);
        //}

        ///// <summary>
        ///// BlowFish-CBC加密
        ///// </summary>
        ///// <param name="str"></param>
        ///// <returns></returns>
        //public static string BlowFish_Encrypt_CBC(this string str, string key)
        //{
        //    if (string.IsNullOrWhiteSpace(str)) return string.Empty;

        //    return new BlowFish(key).Encrypt_CBC(str);
        //}

        ///// <summary>
        ///// BlowFish-CBC解密
        ///// </summary>
        ///// <param name="str"></param>
        ///// <returns></returns>
        //public static string BlowFish_Decrypt_CBC(this string str, string key)
        //{
        //    if (string.IsNullOrWhiteSpace(str)) return string.Empty;

        //    return new BlowFish(key).Decrypt_CBC(str);
        //}

        ///// <summary>
        ///// BlowFish-ECB加密
        ///// </summary>
        ///// <param name="str"></param>
        ///// <returns></returns>
        //public static string BlowFish_Encrypt_ECB(this string str, string key)
        //{
        //    if (string.IsNullOrWhiteSpace(str)) return string.Empty;

        //    return new BlowFish(key).Encrypt_ECB(str);
        //}

        ///// <summary>
        ///// BlowFish-ECB解密
        ///// </summary>
        ///// <param name="str"></param>
        ///// <returns></returns>
        //public static string BlowFish_Decrypt_ECB(this string str, string key)
        //{
        //    if (string.IsNullOrWhiteSpace(str)) return string.Empty;

        //    return new BlowFish(key).Decrypt_ECB(str);
        //}
        //#endregion

        #region 数据库扩展


        public static String RowField(this DataRow row, String fieldname)
        {
            if (Convert.IsDBNull(row[fieldname]))
            {
                return String.Empty;
            }
            return Convert.ToString(row[fieldname]);
        }

        public static bool RowFieldBool(this DataRow row, String fieldname)
        {
            try
            {
                if (Convert.IsDBNull(row[fieldname]))
                {
                    return false;
                }

                String s = row[fieldname].ToString();

                return (s.Equals("TRUE", StringComparison.InvariantCultureIgnoreCase) ||
                        s.Equals("YES", StringComparison.InvariantCultureIgnoreCase) ||
                        s.Equals("1", StringComparison.InvariantCultureIgnoreCase));
            }
            catch
            {
                return false;
            }
        }

        public static Byte RowFieldByte(this DataRow row, String fieldname)
        {
            try
            {
                if (Convert.IsDBNull(row[fieldname]))
                {
                    return 0;
                }
                return Convert.ToByte(row[fieldname]);
            }
            catch
            {
                return 0;
            }
        }

        public static String RowFieldGUID(this DataRow row, String fieldname)
        {
            try
            {
                if (Convert.IsDBNull(row[fieldname]))
                {
                    return String.Empty;
                }
                return Convert.ToString(row[fieldname]);
            }
            catch
            {
                return String.Empty;
            }
        }

        public static int RowFieldInt(this DataRow row, String fieldname)
        {
            try
            {
                if (Convert.IsDBNull(row[fieldname]))
                {
                    return 0;
                }
                return Convert.ToInt32(row[fieldname]);
            }
            catch
            {
                return 0;
            }
        }

        public static long RowFieldLong(this DataRow row, String fieldname)
        {
            try
            {
                if (Convert.IsDBNull(row[fieldname]))
                {
                    return 0;
                }
                return Convert.ToInt64(row[fieldname]);
            }
            catch
            {
                return 0;
            }
        }

        public static Single RowFieldSingle(this DataRow row, String fieldname)
        {
            try
            {
                if (Convert.IsDBNull(row[fieldname]))
                {
                    return 0.0F;
                }
                return Convert.ToSingle(row[fieldname]);
            }
            catch
            {
                return 0.0F;
            }
        }

        public static Double RowFieldDouble(this DataRow row, String fieldname)
        {
            try
            {
                if (Convert.IsDBNull(row[fieldname]))
                {
                    return 0.0F;
                }
                return Convert.ToDouble(row[fieldname]);
            }
            catch
            {
                return 0.0F;
            }
        }

        public static Decimal RowFieldDecimal(this DataRow row, String fieldname)
        {
            try
            {
                if (Convert.IsDBNull(row[fieldname]))
                {
                    return System.Decimal.Zero;
                }
                return Convert.ToDecimal(row[fieldname]);
            }
            catch
            {
                return System.Decimal.Zero;
            }
        }


        public static DateTime RowFieldDateTime(this DataRow row, String fieldname)
        {
            try
            {
                if (Convert.IsDBNull(row[fieldname]))
                {
                    return System.DateTime.MinValue;
                }
                return Convert.ToDateTime(row[fieldname], USCulture);
            }
            catch
            {
                return System.DateTime.MinValue;
            }
        }

        // ----------------------------------------------------------------
        //
        // SIMPLE RS FIELD ROUTINES
        //
        // ----------------------------------------------------------------

        public static String RSField(this IDataReader rs, String fieldname)
        {
            try
            {
                int idx = rs.GetOrdinal(fieldname);
                if (rs.IsDBNull(idx))
                {
                    return String.Empty;
                }
                return rs.GetString(idx);
            }
            catch
            {
                return String.Empty;
            }
        }

        public static bool RSFieldBool(this IDataReader rs, String fieldname)
        {
            try
            {
                int idx = rs.GetOrdinal(fieldname);
                if (rs.IsDBNull(idx))
                {
                    return false;
                }

                String s = rs[fieldname].ToString();

                return (s.Equals("TRUE", StringComparison.InvariantCultureIgnoreCase) ||
                        s.Equals("YES", StringComparison.InvariantCultureIgnoreCase) ||
                        s.Equals("1", StringComparison.InvariantCultureIgnoreCase));
            }
            catch
            {
                return false;
            }
        }

        public static String RSFieldGUID(this IDataReader rs, String fieldname)
        {
            try
            {
                int idx = rs.GetOrdinal(fieldname);
                if (rs.IsDBNull(idx))
                {
                    return String.Empty;
                }
                return rs.GetGuid(idx).ToString();
            }
            catch
            {
                return String.Empty;
            }
        }

        public static Guid RSFieldGUID2(this IDataReader rs, String fieldname)
        {
            try
            {
                int idx = rs.GetOrdinal(fieldname);
                if (rs.IsDBNull(idx))
                {
                    return new Guid("00000000000000000000000000000000");
                }
                return rs.GetGuid(idx);
            }
            catch
            {
                return new Guid("00000000000000000000000000000000");
            }
        }

        public static Byte RSFieldByte(this IDataReader rs, String fieldname)
        {
            try
            {
                int idx = rs.GetOrdinal(fieldname);
                if (rs.IsDBNull(idx))
                {
                    return 0;
                }
                return rs.GetByte(idx);
            }
            catch
            {
                return 0;
            }
        }

        public static int RSFieldInt(this IDataReader rs, String fieldname)
        {
            try
                {
                    int idx = rs.GetOrdinal(fieldname);
                    if (rs.IsDBNull(idx))
                    {
                        return 0;
                    }
                    return rs.GetInt32(idx);
                }
                catch
                {
                    return 0;
                }
        }

        public static long RSFieldLong(this IDataReader rs, String fieldname)
        {
            try
            {
                int idx = rs.GetOrdinal(fieldname);
                if (rs.IsDBNull(idx))
                {
                    return 0;
                }
                return rs.GetInt64(idx);
            }
            catch
            {
                return 0;
            }
        }

        public static Single RSFieldSingle(this IDataReader rs, String fieldname)
        {
            try
            {
                int idx = rs.GetOrdinal(fieldname);
                if (rs.IsDBNull(idx))
                {
                    return 0.0F;
                }
                return (Single)rs.GetDouble(idx); // SQL server seems to fail the GetFloat calls, so we have to do this
            }
            catch
            {
                return 0.0F;
            }
        }

        public static Double RSFieldDouble(this IDataReader rs, String fieldname)
        {
            try
            {
                int idx = rs.GetOrdinal(fieldname);
                if (rs.IsDBNull(idx))
                {
                    return 0.0F;
                }
                return rs.GetDouble(idx);
            }
            catch
            {
                return 0.0F;
            }
        }

        public static Decimal RSFieldDecimal(this IDataReader rs, String fieldname)
        {
            try
            {
                int idx = rs.GetOrdinal(fieldname);
                if (rs.IsDBNull(idx))
                {
                    return System.Decimal.Zero;
                }
                return rs.GetDecimal(idx);
            }
            catch
            {
                return System.Decimal.Zero;
            }
        }

        public static DateTime RSFieldDateTime(this IDataReader rs, String fieldname)
        {
            try
            {
                int idx = rs.GetOrdinal(fieldname);
                if (rs.IsDBNull(idx))
                {
                    return System.DateTime.MinValue;
                }
                return Convert.ToDateTime(rs[idx], USCulture);

            }
            catch
            {
                return System.DateTime.MinValue;
            }
        }

        #endregion

        public static string GetJoinSql(this List<string> obj) {
            if (obj.Count > 0)
            {
                string str = "";
                foreach (var item in obj)
                {
                    str +="'" + item + "',";
                }
                return str.Substring(0, str.Length - 1);
            }
            return "";
        }
    }
}
